package com.viknix.threadpool.manager.client.builder;

import com.viknix.threadpool.manager.client.config.ThreadPoolBuilderGroupSequenceProvider;
import com.viknix.threadpool.manager.client.core.DynamicThreadPoolExecutor;
import com.viknix.threadpool.manager.client.enums.BlockingQueueEnum;
import com.viknix.threadpool.manager.client.enums.RejectedTypeEnum;
import com.viknix.threadpool.manager.client.template.DynamicThreadPoolExecutorTemplate;
import com.viknix.threadpool.manager.client.template.ThreadPoolExecutorTemplate;
import javafx.util.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.group.GroupSequenceProvider;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.concurrent.*;

/**
 * @Author: Dongqi
 * @Date: 2021/10/21 16:26
 * @Version 1.0
 * @Description:
 */
@GroupSequenceProvider(ThreadPoolBuilderGroupSequenceProvider.class)
@Data
@Validated
@Accessors(chain = true)
public class ThreadPoolBuilder implements Builder<ThreadPoolExecutor> {

    /**
     * 是否动态线程池
     */
    private boolean isDynamicThreadPool;

    /**
     * 核心线程数量：默认CPU核数
     */
    private Integer corePoolSize = Runtime.getRuntime().availableProcessors();

    /**
     * 最大线程数量（默认比核心线程数多0.5倍）
     */
    private Integer maxPoolSize = corePoolSize + (corePoolSize >> 1);

    /**
     * 线程存活时间
     */
    private long keepAliveTime = 10000L;

    /**
     * 线程存活时间单位
     */
    private TimeUnit timeUnit = TimeUnit.MILLISECONDS;

    /**
     * 队列容量
     */
    @NotNull(message = "capacity 不能为空！", groups = ThreadPoolBuilder.IsArrayBlockingQueue.class)
    private Integer capacity;

    /**
     * 阻塞队列code
     *
     * @see BlockingQueueEnum
     */
    @NotNull(message = "阻塞队列类型不能为空")
    private Integer blockingQueueCode;

    /**
     * 线程池任务满时拒绝任务策略：默认拒绝任务并抛出异常
     */
    private Integer rejectedHandlerCode = RejectedTypeEnum.ABORT_POLICY.getCode();

    /**
     * 是否守护线程
     */
    private boolean isDaemon;

    /**
     * 线程优先级
     */
    @Range(min = 0, max = 10, message = "线程优先级范围为0 ~ 10")
    private Integer priority = 5;

    /**
     * 线程池id
     */
    @NotBlank(message = "线程池id不能为空！", groups = ThreadPoolBuilder.IsDynamicThreadPool.class)
    private String threadPoolId;

    /**
     * 用于线程创建的线程工厂类
     */
    private ThreadFactory threadFactory;

    /**
     * 线程名称前缀
     */
    private String threadNamePrefix = threadPoolId;

    /**
     * 是否告警
     */
    private boolean isAlert;

    /**
     * 容量告警阈值
     */
    @Range(min = 0, max = 100, message = "容量范围在0 ~ 100之间", groups = ThreadPoolBuilder.IsDynamicThreadPool.class)
    private Integer capacityAlert = 80;

    /**
     * 活跃度告警阈值
     */
    @Range(min = 0, max = 100, message = "活跃度范围在0 ~ 100之间", groups = ThreadPoolBuilder.IsDynamicThreadPool.class)
    private Integer livenessAlert = 80;

    public ThreadPoolBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
        this.keepAliveTime = keepAliveTime;
        this.timeUnit = timeUnit;
        return this;
    }

    public ThreadPoolBuilder alarmConfig(boolean isAlert, int capacityAlert, int livenessAlert) {
        this.isAlert = isAlert;
        this.capacityAlert = capacityAlert;
        this.livenessAlert = livenessAlert;
        return this;
    }

    public DynamicThreadPoolExecutor defaultThreadPool(String threadPoolId) {
        return (DynamicThreadPoolExecutor) ThreadPoolBuilder.builder()
                .setDynamicThreadPool(true)
                .setThreadPoolId(threadPoolId)
                .setThreadNamePrefix(threadPoolId)
                .setCorePoolSize(4)
                .setMaxPoolSize(8)
                .keepAliveTime(1000L, TimeUnit.SECONDS)
                .setBlockingQueueCode(BlockingQueueEnum.LINKED_BLOCKING_QUEUE.getCode())
                .alarmConfig(true, 80, 80)
                .build();
    }


    public static ThreadPoolBuilder builder() {
        return new ThreadPoolBuilder();
    }

    @Override
    public ThreadPoolExecutor build() {
        if (isDynamicThreadPool) {
            return buildCustomPool(this);
        }
        return buildPool(this);
    }

    /**
     * 构建 ThreadPoolExecutor 线程池
     * {@link java.util.concurrent.ThreadPoolExecutor}
     *
     * @param threadPoolBuilder 线程池建造器
     * @return ThreadPoolExecutor 线程池对象
     */
    private ThreadPoolExecutor buildPool(ThreadPoolBuilder threadPoolBuilder) {
        return ThreadPoolExecutorTemplate.getInstance().createThreadPoolExecutor(threadPoolBuilder);
    }

    /**
     * 构建 DynamicThreadPoolExecutor 线程池
     * {@link com.viknix.threadpool.manager.client.core.DynamicThreadPoolExecutor}
     *
     * @param threadPoolBuilder 线程池建造器
     * @return DynamicThreadPoolExecutor 线程池对象
     */
    private ThreadPoolExecutor buildCustomPool(ThreadPoolBuilder threadPoolBuilder) {
        return DynamicThreadPoolExecutorTemplate.getInstance().createThreadPoolExecutor(threadPoolBuilder);
    }

    public interface IsDynamicThreadPool {
    }

    public interface IsArrayBlockingQueue {
    }
}
